package commpackage;

import java.net.*;
import java.io.*;
import java.util.*;
import javax.net.*;
import javax.net.ssl.*;

public class ConnectionThread implements Runnable {

	private SessionCallback sessionCB;
	private ConnectionType connType;
	private Socket connection;
	private ServerSocket sconnection;
	private boolean connect;
	private boolean readMessage;
	private Vector msgQueue;
	private Serializable retObject;
	private boolean stop;
	private int message_id;
	private boolean wait_conn;
	private boolean disconnect;
	private ObjectOutputStream oos;
	private ObjectInputStream ois;
	private ObjectInputStream sois;
	private int sendrec_id;

	public ConnectionThread(int message_id, SessionCallback cb, ConnectionType type)
	{
		sessionCB = cb;
		connType = type;
		stop = false;
		connect = false;
		msgQueue = new Vector();
		connection=null;
		oos=null;
		ois=null;
		retObject=null;
		sendrec_id=0;
		disconnect=false;
		wait_conn=false;
	}

	public synchronized void startSession()
	{
		connect = true;
	}

	public synchronized void endSession()
	{
		disconnect = true;
	}

	public synchronized void getConnections()
	{
		wait_conn = true;
	}

	public synchronized int sendObject(Serializable obj)
	{
		msgQueue.addElement((Serializable)obj);
		return sendrec_id++;
	}

	public synchronized int receiveObject()
	{
		readMessage=true;
		return sendrec_id++;
	}

	public void run() {

		try {
			while(stop != true)
			{
				synchronized(this)
				{
					if(connect)
					{
						try
						{
							if(!connType.isServer())
							{
								if(connType.getSecurity())
								{
									SocketFactory socketFactory = SSLSocketFactory.getDefault();
									connection = socketFactory.createSocket(connType.getHostname(), connType.getPort());
								}
								else
									connection = new Socket(connType.getHostname(),connType.getPort());
							}
							else
							{
								if(connType.getSecurity())
								{
									ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
							        sconnection = ssocketFactory.createServerSocket(connType.getPort());
								}
								else
								{
									sconnection = new ServerSocket(connType.getPort());
								}
							}
							connect=false;
						}
						catch(Exception e)
						{
							System.out.println("Connection Error");
							if(this.sessionCB != null)
								this.sessionCB.onSendError(message_id,e.getMessage(), true);
							stop=true;
						}
					}
					else if(connType.isServer() && !disconnect && wait_conn)
					{
						System.out.println("Server waiting for a connection");
						Socket client = sconnection.accept();
						if(sois == null)
							sois = new ObjectInputStream(client.getInputStream());
						retObject = (Serializable)sois.readObject();
						if(this.sessionCB != null)
							this.sessionCB.onReceive(message_id,retObject);
					}

					if(this.msgQueue.size() > 0)
					{
						try
						{
							if(oos == null)
								oos = new ObjectOutputStream(connection.getOutputStream());

							oos.writeObject((Serializable)msgQueue.remove(0));
							oos.flush();
						}
						catch(IOException e)
						{
							if(sessionCB != null)
								this.sessionCB.onSendError(message_id,e.getMessage(),false);
						}
					}
					else if(readMessage)
					{
						try
						{
							if(ois == null)
								ois = new ObjectInputStream(connection.getInputStream());
							retObject = (Serializable)ois.readObject();
							if(this.sessionCB != null)
								this.sessionCB.onReceive(message_id,retObject);
						}
						catch(IOException e)
						{
							if(this.sessionCB != null)
								this.sessionCB.onReceiveError(message_id,e.getMessage(),false);
						}
						readMessage=false;
					}
					else if(disconnect)
					{
						if(connType.isServer())
						{
							sois.close();
							sconnection.close();
						}
						else
						{
							connection.close();
							ois.close();
							oos.close();
						}
						stop=true;
					}
				}
				Thread.sleep(50); // We dont eat up the cpu.
			}
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
			this.sessionCB.onSendError(message_id,e.getMessage(), true);
		}
	}
}
